package com.iflytek.aisol.audit.iflytek.strategy.manage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.PageHelper;
import com.iflytek.aisol.audit.iflytek.strategy.manage.config.CustomException;
import com.iflytek.aisol.audit.iflytek.strategy.manage.constant.TableColumnInitConstant;
import com.iflytek.aisol.audit.iflytek.strategy.manage.dto.GrayConfigDTO;
import com.iflytek.aisol.audit.iflytek.strategy.manage.mapper.*;
import com.iflytek.aisol.audit.iflytek.strategy.manage.mapper.fr.FrGrayConfigChannelMapper;
import com.iflytek.aisol.audit.iflytek.strategy.manage.mapper.fr.FrGrayConfigServerInstanceMapper;
import com.iflytek.aisol.audit.iflytek.strategy.manage.query.PageDTO;
import com.iflytek.aisol.audit.iflytek.strategy.manage.service.GrayConfigService;
import com.iflytek.aisol.audit.iflytek.strategy.manage.entity.*;
import com.iflytek.aisol.audit.iflytek.strategy.manage.query.GrayConfigQuery;
import com.iflytek.aisol.audit.iflytek.strategy.manage.query.GrayConfigVO;
import com.iflytek.aisol.audit.iflytek.strategy.manage.utils.ConfigValidationUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author zxwu17
 */
@Service
@RequiredArgsConstructor
public class GrayConfigServiceImpl implements GrayConfigService {

    private final GrayConfigMapper grayConfigMapper;
    private final ServiceConfigMapper serviceConfigMapper;
    private final FrGrayConfigServerInstanceMapper frGrayConfigServerInstanceMapper;
    private final ChannelConfigMapper channelConfigMapper;
    private final FrGrayConfigChannelMapper frGrayConfigChannelMapper;
    private final ConfigValidationUtil configValidationUtil;
    /**
     * 新增灰度配置服务
     * @param grayConfigDTO
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void add(GrayConfigDTO grayConfigDTO) {
        GrayConfig grayConfig = BeanUtil.toBean(grayConfigDTO, GrayConfig.class);
        grayConfig.setGrayConfig(JSONUtil.toJsonStr(grayConfigDTO.getGrayConfig()));
        String type = grayConfigDTO.getGrayType();

        // 将结果保存到数据库
        grayConfigMapper.save(grayConfig);
        // grayConfig.getGrayConfig() 的格式校验
        // 从数据库引擎表检查grayConfig字段类型是否合法，合法将输入的字段类型写入引擎表
        configValidationUtil.validateConfig(grayConfigDTO.getGrayConfig(), "grayConfig");

        if(ConfigValidationUtil.isInServerType(type)){
            //插入级联表fr_gray_config_server_instance
            //1 先获取灰度id，主键
            Long id = grayConfig.getId();
            //2 拿grayConfig.getGrayConfig()中的gray_rate字段key(主键)去ServerInstance表查
            // 这里灰度的依赖服务是从  grayConfig.getGrayConfig() 读取的
            String dependentServer = grayConfig.getGrayConfig();
            String dependentServerJson = JSONUtil.toJsonStr(dependentServer);
            // 字符串转map
            Map<String, Object> jsonMap = JSONUtil.toBean(dependentServerJson, Map.class);
            // 获取 gray_rate 的键
            Map<String, Object> grayRate = (Map<String, Object>) jsonMap.get("gray_rate");
            Set<String> instanceIds = grayRate.keySet();
            for(String instanceId:instanceIds){
                // 如果在数据库表ServerInstance中存在的话就写入灰度服务级联表
                if (serviceConfigMapper.findWithInstanceIdAndNoDeleteAndVersionMax(instanceId).isEmpty()) {
                    throw new CustomException("instanceId="+ instanceId +"在数据库是未被启用，不能插入级联表");
                }
                // 存在的话获取该条记录主键
                List<ServerInstance> instance = serviceConfigMapper.findWithInstanceIdAndNoDeleteAndVersionMax(instanceId);
                if(instance.get(0)==null){
                    throw new CustomException("找不到版本最大且未删除的server记录");
                }
                Long server_id = instance.get(0).getId();
                //存在，写入级联表fr_gray_config_server_instance
                FrGrayConfigServerInstance frGrayConfigServerInstance = new FrGrayConfigServerInstance();
                frGrayConfigServerInstance.setServerInstanceId(server_id);
                frGrayConfigServerInstance.setGrayConfigId(id);
                frGrayConfigServerInstanceMapper.save(frGrayConfigServerInstance);
            }
        }else if(ConfigValidationUtil.isInChannelType(type)){
            /*// 将结果保存到数据库
            grayConfigMapper.save(grayConfig);*/
            // 插入级联表fr_gray_config_channel
            //1 先获取灰度id，主键
            Long id = grayConfig.getId();
            //拿grayConfig.getGrayConfig()中的gray_rate字段key(主键)去ChannelConfig表查
            Object dependentChannel = grayConfig.getGrayConfig();
            String dependentChannelJson = JSONUtil.toJsonStr(dependentChannel);
            // 字符串转map
            Map<String, Object> jsonMap = JSONUtil.toBean(dependentChannelJson, Map.class);
            // 获取 gray_rate 的键
            Map<String, Object> grayRate = (Map<String, Object>) jsonMap.get("gray_rate");
            Set<String> channelIds = grayRate.keySet();
            // 这里灰度的依赖channel channelOpt是从  grayConfig.getGrayConfig() 读取的
            for(String channelId:channelIds){
                // 如果在数据库表ServerInstance中存在的话就写入灰度服务级联表
                if (channelConfigMapper.findWithChannelIdAndNoDeleteAndVersionMax(channelId).isEmpty()) {
                    throw new CustomException("该条记录channelId"+channelId+"未启用，不可插入级联表");
                }
                // 存在，取出版本号最大，delete=0记录的主键
                ChannelConfig channelConfig = channelConfigMapper.findWithChannelIdAndNoDeleteAndVersionMax(channelId).get(0);
                if(channelConfig==null){
                    throw new CustomException("找不到版本号最大且未删除的channel记录");
                }
                Long channelConfig_id = channelConfig.getId();
                //存在，写入级联表fr_gray_config_Channel
                FrGrayConfigChannel frGrayConfigChannel = new FrGrayConfigChannel();
                frGrayConfigChannel.setChannelConfigId(channelConfig_id);
                frGrayConfigChannel.setGrayConfigId(id);
                frGrayConfigChannelMapper.save(frGrayConfigChannel);
            }
        }else{
            throw new CustomException(TableColumnInitConstant.ERROR,"灰度类型不匹配");
        }
    }

    /**
     * 删除3张表字段
     * gray_config
     * fr_gray_config_channel
     * fr_gray_config_server_instance
     * @param id 灰度id
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void delete(Long id) {
        //1 删除fr_gray_config_server_instance记录
        frGrayConfigServerInstanceMapper.deleteByGrayId(id);
        //2 删除fr_gray_config_channel记录
        frGrayConfigChannelMapper.deleteByGrayId(id);
        //3 删除灰度配置
        grayConfigMapper.deleteById(id);
    }

    /**
     * 分页查询灰度配置
     * @param query
     * @return
     */
    @Override
    public PageDTO<GrayConfigVO> queryGrayNamePage(GrayConfigQuery query) {
        Integer pageNo = query.getPageNo();
        Integer pageSize = query.getPageSize();
        // 开启分页
        PageHelper.startPage(pageNo,pageSize);
        // 构建分页条件和排序字段
        // 判断是否有排序字段，如果没有就使用默认排序
        Pageable pageable;
        if (StrUtil.isNotBlank(query.getSortBy())) {
            pageable = PageRequest.of(pageNo - 1, pageSize,
                    query.getIsAsc() ? Sort.by(query.getSortBy()).ascending() : Sort.by(query.getSortBy()).descending());
        } else {
            // 默认排序，使用更新时间降序
            pageable = PageRequest.of(pageNo - 1, pageSize, Sort.by("updateTime").descending());
        }
        // 查询数据库
        Page<GrayConfig> page = grayConfigMapper.findAllWithFilters(
                query.getGrayName(), pageable);
        // 封装成VO
        List<GrayConfigVO> GrayVOS = BeanUtil.copyToList(page.getContent(), GrayConfigVO.class);
        // 构建分页DTO
        return new PageDTO<>(page.getTotalElements(), (long) page.getTotalPages(), GrayVOS);
    }


}
